﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using JTextSdd;
using JtextEpicsInterface;
using jtext_EpicsServer;
using System.Collections;
using EpicsJecket;
using System.Text.RegularExpressions;
using LibAutoTransmeter;

//a full packet of JtextIOC 
//includes Jacket and autoTransmeter
namespace Jetest2
{
    class Program
    {


        static void Main(string[] args)
        {
            string WorkingPath = AppDomain.CurrentDomain.BaseDirectory.ToString();
            string SDDFileName;
            JEpicsServer MyJEServer=null;
            EJServer myserver=null;
            //create sdd object
            try
            {
                SDDFileName = args[0];
            }
            catch
            {
                SDDFileName = "sdd.xml";    //use default sdd files
            }
            SDDtoEpics mySdd = new SDDtoEpics(WorkingPath + SDDFileName);
            if (mySdd.IocName != "null")
            {
                #region JIOC With sdd
                //this is a general perpose JEserver With sdd suport


                Console.WriteLine("This is a general perpose JEserver With sdd suport,and with device support.");
                Console.WriteLine("2010-06-03");
                Console.WriteLine("sdd file name as a argument, JSM(Jtext-State-Machine) support");
                Console.WriteLine("2011-11-08");
                Console.WriteLine("enter exit to shutdown");
                MyJEServer = new JEpicsServer(mySdd.IocName, (int)(mySdd.IocInterval)); //create the JEServer

                MyJEServer.LoadDrivers(WorkingPath + "drivers//");
                MyJEServer.LoadPlugIns(WorkingPath + "plugins//");
                #region Ini_device
                Hashtable Table_Device = new Hashtable();
                ArrayList[] Devicelist = mySdd.DevicesRegister();
                foreach (ArrayList dev in Devicelist)
                {   //put device in to device list
                    //the line below should be change to an method that returan a device either s-type or g-type.
                    //JEDevice myDev = GetDevice(dev);
                    JEDevice myDev = new JEDevice((string)dev[0], (string)dev[1], true, MyJEServer);
                    Table_Device.Add((string)dev[0], myDev);
                    Console.WriteLine("Device added:" + (string)dev[0]);
                    try
                    {
                        //load device support
                        myDev.LoadDeviceSupport(WorkingPath + "DeviceSupport//" + myDev.DeviceType + ".dll");
                    }
                    catch
                    {
                        Console.WriteLine("No Device Support for " + myDev.DeviceType);
                    }
                }

                #endregion

                Record_prop[] TRecords;
                TRecords = mySdd.getAllRecord();
                foreach (Record_prop TRecord in TRecords)
                {
                    Console.WriteLine("Add PV " + TRecord.pvName);
                    MyJEServer.AddRecord(TRecord);  //add record 
                    //added to device if needed
                    if (Table_Device.Contains(TRecord.DeviceName))
                    {
                        ((JEDevice)Table_Device[TRecord.DeviceName]).addDeviceProperty(TRecord.DeviceProperty, TRecord.pvName, TRecord.DeviceDtatType);
                    }
                }

                //start the device
                foreach (DictionaryEntry dev in Table_Device)
                {
                    ((JEDevice)(dev.Value)).PublishDevice();
                }

                MyJEServer.DeviceTable = Table_Device;

                MyJEServer.StartServer();

                Console.WriteLine("Server Has Started");
                #endregion
            }

            if (mySdd.servername != "null")
            {
                #region version 3.0 sdd support

                Console.WriteLine("This is a ganerel purpose EpicsJacket Server with JtextSDD support.");
                Console.WriteLine("2011_06_20  Jtext Control Team");

                Console.WriteLine("sdd file name as a argument");
                Console.WriteLine("2011-11-08");
                Console.WriteLine("11111111 special edition with bug fixed now support spliter.");
                Console.WriteLine("2011-11-11");
                Console.WriteLine("Add PlugIn support.");
                Console.WriteLine("2011-11-08");
                Console.WriteLine("Transmeters integrated.");
                Console.WriteLine("2012-02-21");

                string ServerName = mySdd.servername;
                bool isByte = mySdd.isByte;
                int msgLen = mySdd.messageLen;
                byte ending = mySdd.ending;
                int reply_To = mySdd.ReplyTo;
                string Scanner = mySdd.scanner;
                string DefScennerReply = mySdd.DefaultScanner;
                string[] MsgDriver = mySdd.DriverMessage();
                string Spliter = mySdd.Spliter;
                //ordor[DriverFlie,DriverName,DriverPath,timeout,timeoutlimit];

                //EJServer myserver = new EJServer(SERVERNAME, true, 5, 0, EJServer.Reply_to.Scanner);
                myserver = new EJServer(ServerName, isByte, msgLen, ending, (EJServer.Reply_to)reply_To);
                myserver.ConsoleOut = true;

                myserver.LoadDrivers(AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\" + MsgDriver[0], MsgDriver[1], MsgDriver[2]);
                myserver.SetPlugin(AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\EjPlugin.dll");
                myserver.WatchdogTimeout = Convert.ToInt16(MsgDriver[3]);
                myserver.TimeOutTimesLimit = Convert.ToInt16(MsgDriver[4]);
                #region ini scan

                //myserver.addScanVarible(PV_SERVERSTAT, 2, 0, -1, 1);
                //myserver.addScanVarible("p2", 2, 0, -1);

                MessageProp[] MyMsgPropS = mySdd.getAllMessageprop();
                foreach (MessageProp MyMsgProp in MyMsgPropS)
                {
                    myserver.addScanVarible(MyMsgProp);
                    Console.WriteLine("add pv:" + MyMsgProp.pvName);
                }

                if (isByte == true)
                {
                    myserver.ScanCmd = HexStringToBytes(Scanner, " ");
                    myserver.ScanDefaultReply = HexStringToBytes(DefScennerReply, " ");

                }
                else
                {
                    myserver.ScanCmd = Scanner;
                    myserver.ScanDefaultReply = DefScennerReply;
                    if (Spliter != "")
                    {
                        myserver.Spliter = Spliter;
                        Console.WriteLine("The Scanner Splitor is: "+ Spliter);
                    }
                }

                #endregion

                //JEDevice myDev = new JEDevice("DEV:TEST:EJ", "null", true, null);
                //myDev.PublishDevice();

                myserver.OnOutMessage += new EJServer.OutMessageHandler(PrintMsg);

                myserver.StartServer();
                myserver.StartScan(((int)mySdd.scaninterval));


                #endregion

                #region Load Transmeter
                ArrayList transMeters = new ArrayList();

                int i = 1;
                try
                {
                    for (i = 1; i < args.Length; i++)
                    {
                        TranmeterProp Tprop = TranmeterProp.loadMe(WorkingPath + args[i]);
                        Transmeter Trans = new Transmeter(Tprop);
                        Trans.myEJServer = myserver;
                        if (mySdd.Spliter != "")
                        {
                            Trans.Spliter = mySdd.Spliter;
                            Console.WriteLine("The AutoTrans Splitor is: "+ Spliter);
                        }
                        Trans.IniTransmeter();
                        transMeters.Add(Trans);
                        Console.WriteLine("transmeter: " + args[i].ToString());
                    }
                }
                catch(SystemException e)
                {
                    Console.WriteLine("no transmeter, message: "+e.Message);
                }


                #endregion
            }

            //keep the proc
            while (true)
            {

                //Thread.Sleep(1000);
                string cmd= Console.ReadLine();
                //cli code here
                if (cmd == "exit")
                {
                    MyJEServer.DisposeAllRecord();
                    myserver.DisposeServer();
                }
                else
                {
                    Console.WriteLine("Unknow Command");
                }
                //MyJEServer.BenchFlush();
            }


        }



        #region server_envent

        /// <summary>
        /// server recieve msg from client
        /// </summary>
        /// <param name="msg">The MSG.</param>
        public static void PrintMsg(object msg, bool isByte, EJServer.Reply_to From_whog)
        {
            string Str_msg;
            if (isByte == true)
            {

                Str_msg = BytesToHexString((byte[])msg, " ");
            }
            else
            {
                Str_msg = (string)msg;
            }
            //Console.WriteLine("ass");
            Console.WriteLine(From_whog.ToString() + " : " + Str_msg);
        }

        #endregion

        #region additionnal
        /// <summary>
        /// make a string that contains many hex numbers splited by spliter to byte[]
        /// </summary>
        /// <param name="HexString">The hex string.</param>
        /// <param name="spliter">The spliter.</param>
        /// <returns></returns>
        public static byte[] HexStringToBytes(string HexString, string spliter)
        {
            byte[] tBytes;
            string[] tVals = Regex.Split(HexString, spliter, RegexOptions.IgnoreCase);
            tBytes = new byte[tVals.Length];
            for (int i = 0; i < tVals.Length; i++)
            {
                tBytes[i] = Convert.ToByte(tVals[i], 16);
            }
            return tBytes;
        }

        /// <summary>
        /// make byte array to a string .
        /// </summary>
        /// <param name="BytesArray">The bytes array.</param>
        /// <param name="spliter">The spliter.</param>
        /// <returns></returns>
        public static string BytesToHexString(byte[] BytesArray, string spliter)
        {
            string StrOut = "";
            for (int m = 0; m < BytesArray.Length; m++)
            {
                StrOut = StrOut + (BytesArray[m].ToString("X2") + spliter);
            }
            return StrOut;
        }

        #endregion



    }



}
